package com.proxyforgame.lifesim;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JPanel;

/**
 * The View of LifeSim with the editor.
 * Left mouse button sets cells, right one resets cells. Editing is available even when simulation is running.
 */
public class LifeView extends JPanel {

	private static final long	serialVersionUID	= -7705111475296001684L;

	private LifeModel			model				= null;

	/**
	 * Screen size of a cell.
	 */
	private int					cellSize			= 8;

	/**
	 * Gap between cells.
	 */
	private int					cellGap				= 1;

	/**
	 * Color of a dead cell.
	 */
	private static final Color	c0					= new Color(0x505050);

	/**
	 * Color of an alive cell.
	 */
	private static final Color	c1					= new Color(0xFFFFFF);

	public LifeView(LifeModel pmodel, int cellSize, int cellGap) {
		this.cellSize = cellSize;
		this.cellGap = cellGap;
		model = pmodel;

		setBackground(Color.BLACK);

		// field editor
		MouseAdapter ma = new Editor();
		addMouseListener(ma);
		addMouseMotionListener(ma);
	}

	/* 
	 * Returns the preferred panel size based on field width and height, cell size and gap.
	 */
	@Override
	public Dimension getPreferredSize() {
		Insets b = getInsets();
		return new Dimension((cellSize + cellGap) * model.getWidth() + cellGap + b.left + b.right,
							(cellSize + cellGap) * model.getHeight() + cellGap + b.top + b.bottom);
	}

	/* 
	 * Repaints the view contents.
	 * Synchronization is used in order to avoid repainting of the field that is being changed.
	 */
	@Override
	protected void paintComponent(Graphics g) {
		synchronized (model) {
			super.paintComponent(g);
			Insets b = getInsets();
			for (int y = 0; y < model.getHeight(); y++) {
				for (int x = 0; x < model.getWidth(); x++) {
					byte c = model.getCell(x, y);
					g.setColor(c == 1 ? c1 : c0);
					g.fillRect(b.left + cellGap + x * (cellSize + cellGap), b.top + cellGap + y
										* (cellSize + cellGap), cellSize, cellSize);
				}
			}
		}
	}

	/**
	 * Field editor.
	 */
	class Editor extends MouseAdapter {

		private boolean	pressedLeft		= false;
		private boolean	pressedRight	= false;

		@Override
		public void mouseDragged(MouseEvent e) {
			setCell(e);
		}

		@Override
		public void mousePressed(MouseEvent e) {
			if (e.getButton() == MouseEvent.BUTTON1) {
				pressedLeft = true;
				pressedRight = false;
				setCell(e);
			} else if (e.getButton() == MouseEvent.BUTTON3) {
				pressedLeft = false;
				pressedRight = true;
				setCell(e);
			}
		}

		@Override
		public void mouseReleased(MouseEvent e) {
			if (e.getButton() == MouseEvent.BUTTON1) {
				pressedLeft = false;
			} else if (e.getButton() == MouseEvent.BUTTON3) {
				pressedRight = false;
			}
		}

		/**
		 * Sets or resets a cell pointed by mouse.
		 */
		private void setCell(MouseEvent e) {
			synchronized (model) {
				// get the coordinates of a cell pointed by mouse
				int x = e.getX() / (cellSize + cellGap);
				int y = e.getY() / (cellSize + cellGap);
				if (x >= 0 && y >= 0 && x < model.getWidth() && y < model.getHeight()) {
					if (pressedLeft == true) {
						model.setCell(x, y, (byte) 1);
						repaint();
					}
					if (pressedRight == true) {
						model.setCell(x, y, (byte) 0);
						repaint();
					}
				}
			}
		}

	}

}
